#include "Level.h"
#include <iostream>


#include <QFileDialog>
#include <fstream>
#include <TextureManager.h>


// think about creating a time out save event

Level::Level()
    :
    m_currentLayer(0),
    m_width(0),
    m_height(0),
    m_layers(0),
    m_allocated(false)
{
    m_imageDir = "4x4.png"; // the default image so it dosent render nothing
    m_showLayer[0] = true;
    for(int i = 1; i< 4; i++)
        m_showLayer[i] = false;
    mySize = 8;
}

Level::~Level()
{
    DeAllocate();
}

bool Level::IsShowen(int layer)
{
    return m_showLayer[layer];
}

void Level::ShowLayer(int layer, bool show)
{
    m_showLayer[layer] = show;
}


void Level::Allocate(int l, int w, int h)
{

    m_layers = l; m_width = w; m_height = h;

    m_allocated = true;


}

void Level::DeAllocate()
{
    m_layers =0 ; m_width = 0; m_height = 0;
    m_allocated = false;
}

void Level::Render(int left, int top)
{
    glEnable(GL_BLEND);
    for(int l = 0; l < m_layers; l++)
    {
        if(this->IsShowen(l))
        {
            for(int w = 0; w < m_width; w++)
            {
                for(int h = 0; h < m_height; h++)
                {
                    if(m_tile[l][w][h].placed)
                        m_tile[l][w][h].Render(left, top);
                }
            }
        }
    }
}

void Level::SaveDS(std::string name)
{
    QString filename = QFileDialog::getSaveFileName(0, "Save you Map", "", "*.h");
    std::ofstream file;
    file.open(filename.toStdString().c_str(), std::ios::out);
    m_layers = 1;
    file << "static uint32 " << name << " [" << m_width*m_height << "] " << " = "  << " {" << std::endl;
    for(int x = 0; x < m_width; x++)
    {
        for(int y = 0; y < m_height; y++)
        {
            if(m_tile[0][x][y].ID == -1)
                m_tile[0][x][y].ID = 0;
            file << m_tile[0][x][y].ID << ",";
        }
        file << std::endl;
    }
    file << " }" << std::endl;

    file.close();
}


void Level::LoadDS(std::string filename, TileSheet &sheet)
{
    std::ifstream file;
    file.open(filename.c_str(), std::ios::in);
    m_layers = 1;

    int id;
    file >> m_imageDir;

    sheet.SetImage(m_imageDir);
    file >> m_width;
    file >> m_height;

    Allocate(m_layers, m_width, m_height);

    for(int l =0; l < m_layers; l++)
    {
        for(int x = 0; x < m_width; x++)
        {
            for(int y = 0; y < m_height; y++)
            {
                file >> id;
                TileRect rect;

                m_tile[l][x][y].ID = id;

                if(id == -1)
                {
                    m_tile[l][x][y].placed = false;
                    rect = sheet.GetRect(0);
                }
                else
                {
                    m_tile[l][x][y].placed = true;
                    rect = sheet.GetRect(id);
                }
                m_tile[l][x][y].SetImage(*TextureManager::GetInst()->GetTexture(m_imageDir));
                m_tile[l][x][y].image.SetClip(rect.x, rect.y);
                m_tile[l][x][y].image.SetPosition(x*mySize, y*mySize);
            }
        }
    }


    file.close();

}

void Level::Load(std::string filename, TileSheet& sheet)
{

    std::ifstream file;
    file.open(filename.c_str(), std::ios::in);
    m_layers = 4;

    int id;
    file >> m_imageDir;

    sheet.SetImage(m_imageDir);
    file >> m_width;
    file >> m_height;

    Allocate(m_layers, m_width, m_height);

    for(int l =0; l < m_layers; l++)
    {
        for(int x = 0; x < m_width; x++)
        {
            for(int y = 0; y < m_height; y++)
            {
                file >> id;
                TileRect rect;

                m_tile[l][x][y].ID = id;

                if(id == -1)
                {
                    m_tile[l][x][y].placed = false;
                    rect = sheet.GetRect(0);
                }
                else
                {
                    m_tile[l][x][y].placed = true;
                    rect = sheet.GetRect(id);
                }
                m_tile[l][x][y].SetImage(*TextureManager::GetInst()->GetTexture(m_imageDir));
                m_tile[l][x][y].image.SetClip(rect.x, rect.y);
                m_tile[l][x][y].image.SetPosition(x*mySize, y*mySize);
            }
        }
    }


    file.close();
}



void Level::Save(TileSheet& sheet)
{
    QString filename = QFileDialog::getSaveFileName(0, "Save you Map", "", "*.map");
    std::ofstream file;
    file.open(filename.toStdString().c_str(), std::ios::out);
    m_layers = 4;
    file << m_imageDir << std::endl;
    file << m_width << std::endl;
    file << m_height << std::endl;
    file << std::endl;

    for(int l =0; l < m_layers; l++)
    {
        for(int x = 0; x < m_width; x++)
        {
            for(int y = 0; y < m_height; y++)
            {
                file << m_tile[l][x][y].ID << std::endl;
            }
        }
    }

    file.close();
}

void Level::New(int width, int height, std::string mapName)
{
    m_mapName = mapName;
    Allocate(4,width,height);  /// @todo create a new box for this ( lol )
    SetUpTiles();
}

void Level::PlaceTile(int mouseX, int mouseY, int layer, TileSheet& sheet)
{
    // "offset your stupid with some smart" i just heard that on tv lol

    TileRect imageRect = sheet.GetSelected();


    if(mouseX < 32)
        mouseX = 0;
    if(mouseY < 32)
        mouseY = 0;

    int X = 0;
    int Y = 0;

    for(int x = 0; x < m_width; x++)
    {
        for(int y = 0; y < m_height; y++)
        {
            if(m_tile[0][x][y].Contains(x*mySize, y*mySize, mouseX, mouseY))
            {
                X = x*mySize;
                Y = y*mySize;
                break;
            }
        }
    }

    if(X < mySize)
        X = 0;
    if( Y < mySize)
        Y = 0; // round down

    X /= mySize;
    Y /= mySize;

    if(X >= m_width || Y >= m_height || X < 0 || Y < 0)
        return;

    /// @todo change the 0's back to layer when supported

    m_tile[m_currentLayer][X][Y].ID = sheet.GetTileID();
    m_tile[m_currentLayer][X][Y].placed = true;
    m_tile[m_currentLayer][X][Y].image.SetClip(imageRect.x, imageRect.y, mySize, mySize);


}

bool Level::IsAllocated()
{
    return m_allocated;
}

void Level::SetImageDir(std::string dir)
{
    m_imageDir = dir;
}

void Level::SetUpTiles()
{

    for(int l = 0; l < m_layers; l++)
    {
        for(int w = 0; w < m_width; w++)
        {
            for(int h = 0; h < m_height; h++)
            {
                m_tile[l][w][h].Create(-1);
                m_tile[l][w][h].SetImage(*TextureManager::GetInst()->GetTexture(m_imageDir));
                m_tile[l][w][h].image.SetClip(0, 0);
                m_tile[l][w][h].image.SetPosition(w*mySize, h*mySize);
            }
        }
    }
}
